
local Element = commonlib.getfield("Window.Elements.Element");
local Select = commonlib.inherit(Element);

Select:Property("Options");
Select:Property("Value");
Select:Property("Label");
Select:Property("HoverIndex", 0);
Select:Property("SelectedIndex", 0);
Select:Property("DefaultStyle", "line-height: 30px;");
Select:Property("BGColor", 0xffffffff);

function Select:Init(xmlnode, window, parent)
    self:InitElement(xmlnode, window, parent);

    self:OnAttrValueChange("options");
    self:OnAttrValueChange("value");

    return self;
end

function Select:OnAttrValueChange(attrName)
    if (attrName == "options") then
        local attr_options = self:GetAttrTableValue("options");
        local options = {};
        for _, option in ipairs(attr_options) do
            if (type(option) == "string") then 
                table.insert(options, {option, option}); 
            elseif (type(option) == "table") then
                table.insert(options, {option[1] or option.label, option[2] or option.value});
            end
        end
        self:SetOptions(options);
    elseif (attrName == "value") then
        local value = self:GetAttrStringValue("value");
        for index, option in ipairs(self:GetOptions()) do
            if (option[2] == value) then 
                self:SetSelectedIndex(index);
                break;
            end
        end
    end
end

function Select:OnUpdateLayout()
    Select._super.OnUpdateLayout(self);

    local maxWidth = 0;
    local options = self:GetOptions();
    for _, option in ipairs(options) do
        local textWidth = self:GetTextWidth(option[1]);
        maxWidth = maxWidth < textWidth and textWidth or maxWidth;
    end
    maxWidth = maxWidth + 40;
    local contentHeight = (#options) * self:GetLineHeight();
    local maxHeight = math.min(400, contentHeight);
    local parentWidth, parentHeight = self:GetParent():GetLayout():GetWidthHeight();
    self:GetLayout():SetPos(parentWidth / 2 - maxWidth / 2, parentHeight + 20);
    self:GetLayout():SetWidthHeight(maxWidth, math.max(maxHeight, 40));
    self:GetLayout():SetRealContentWidthHeight(maxWidth, contentHeight);
end

function Select:Render()
    -- 绘制下拉列表
    local options = self:GetOptions();
    local x, y, w, h = self:GetPosition();
    local _, realContentHeight = self:GetRealContentWidthHeight();
    local line_height = self:GetLineHeight();
    local height = math.min(realContentHeight, h);
    local is_overflow = realContentHeight > h;
    local opt_x, opt_y = self:GetContentPosition();
    
    -- self:SetPenStringColor(0x0, 0x0, 0x0, 0xff);
    self:SetBrushColor(self:GetBGColor());
    self:DrawRectangle(x, y, w, height);
    self:SetFont(self.__style_font_weight__, self.__style_font_slant__, self.__style_font_family__);
    self:SetFontSize(self.__style_font_size__);
    self:SetFontColor(0xffffffff);
    if (is_overflow) then
        self:Save();
        self:DrawRectangle(x, opt_y, w, height, false, false);
        self:Clip();
        self:Translate(-self.__scroll_x__, -self.__scroll_y__);
    end
    local hoverIndex = self:GetHoverIndex();
    local selectedIndex = self:GetSelectedIndex();
    for index, option in ipairs(options) do
        if (hoverIndex == index) then
            self:SetBrushColor(0x40); -- 悬浮项背景色
            self:DrawRectangle(x + 2, opt_y + 2, w - 4, line_height - 4);
        end
        self:DrawText(opt_x + 30, opt_y, w, line_height, option[1]);
        if (selectedIndex == index) then
            self:SetBrushColor(0xff);
            self:DrawCircle(opt_x + 15, opt_y + line_height / 2, 5);
        end
        opt_y = opt_y + line_height;
    end

    if (is_overflow) then
        self:Translate(self.__scroll_x__, self.__scroll_y__);
        self:Restore();
    end

    local arrow_size = 8;
    self:SetBrushColor(self:GetBGColor());
    self:DrawTriangle(x + w / 2 - arrow_size, y, x + w / 2 + arrow_size, y, x + w / 2, y - arrow_size);
end

function Select:GetOptionIndex(event)
    local options = self:GetOptions();
    local max_index = #options;
    local scrollX, scrollY = self:GetScrollXY();
    local x, y = event:GetXY();
    local relx, rely = self:ScreenXYToElementXY(x, y);
    local line_height = self:GetLineHeight();
    return math.max(1, math.min(max_index, math.ceil((rely + scrollY) / line_height)));
end

function Select:OnMouseMove(event)
    event:Accept();
    self:SetHoverIndex(self:GetOptionIndex(event));
end

function Select:OnMouseWheel(event)
    event:Accept();
    Select._super.OnMouseWheel(self, event);
    self:SetHoverIndex(self:GetOptionIndex(event));
end

function Select:OnMouseDown(event)
    event:Accept();
    self:CaptureMouse();
end

function Select:OnMouseUp(event)
    event:Accept();
    self:ReleaseMouse();
    self:Hide();
    local optionIndex = self:GetOptionIndex(event);
    local option = self:GetOptions()[optionIndex];
    self:SetSelectedIndex(optionIndex);
    self:SetValue(option[2]);
    self:SetLabel(option[1])
    self:OnChange();
    self:FocusOut();
end


function Select:OnFocusIn()
    Select._super.OnFocusIn(self);
    self:Show();
end

function Select:OnChange()
    self:CallAttrFunction("onchange", nil, self:GetValue(), self:GetLabel());
end

return Select;
